﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using MOJsdk;
using System.Threading;
using System.Windows.Threading;
using IO = System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

namespace MOJ
{
    /// <summary>
    /// Interaction logic for Control_OrganizeMovies.xaml
    /// </summary>
    public partial class Control_OrganizeMovies : UserControl
    {
        #region Vars
        private bool IsLoading = false;
        private List<MOJFile> ListFiles;
        private List<MOJMovie> Movies;
        private MOJOrganizeRules _rules;
        #endregion

        #region INI
        public Control_OrganizeMovies()
        {
            InitializeComponent();
            INI();
        }
        private void INI()
        {
            _btn_start.Content = MOJLocalization.Localize("Start");
            _btn_preview.Content = MOJLocalization.Localize("Preview");

            _Grid.ApplyStyle("0101152");
            _Prog_isAlive.ApplyStyle("0101153");
            _Prog_progress.ApplyStyle("0101154");
            _ListBox.ApplyStyle("0101155");
            _btn_start.ApplyStyle("0101156");
            _btn_preview.ApplyStyle("0101165");

            this.Loaded += OnLoaded;
            _btn_start.Click += StartProcess;
            _btn_preview.Click += StartPreview;
        }
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (IsLoading)
                return;
            IsLoading = true;

            GlobalVars.TheHost.ReloadDrivePool();
            _rules = new MOJOrganizeRules();
            if (!_rules.KeepFileDisk && !GlobalVars.TheHost.DrivePool.ContainsKey(_rules.DiskID))
            {
                GlobalVars.TheHost.ReportError(new ErrorReporter()
                {
                    ErrorCode = "NoDiskINPOOL",
                    ErrorMessage = "Please connect destination disk to computer",
                    ErrorDetails = "Change diskID in settings",
                });
                return;
            }

            ListFiles = new List<MOJFile>();
            NoArgs th = new NoArgs(StartPreProcess);
            SetLoadingStatus(true);
            th.BeginInvoke(null, null);
        }
        private void StartPreProcess()
        {
            try
            {
                Movies = new List<MOJMovie>();

                AddListBoxEntry("Loading movies...");
                foreach (var v in GlobalVars.TheHost.LoadMovies())
                    if (v.IsAvaible && !v.IsOrganized)
                        Movies.Add(v);
                AddListBoxEntry(string.Format("Loaded {0} unorganized movies", Movies.Count));

                AddListBoxEntry("Checking files...");
                int prog = 0;
                foreach (var v in Movies)
                {
                    SetProgress(prog++, Movies.Count);
                    AddListBoxEntry(string.Format("{2}/{3} - Cheking files of movie {0} ({1})", v.MovieTitle, v.MovieYear, prog, Movies.Count));

                    List<MOJFile> tempFiles = new List<MOJFile>();
                    foreach (MOJFile f in v.Files)
                    {
                        if (f.FileType != 2)
                            if (!f.IsOrganized)
                            {
                                #region FileDuplicated
                                if (tempFiles.Count(z => z.GetOrganizedPath().ToLower() == f.GetOrganizedPath().ToLower()) > 0)
                                {
                                    int res = -1;
                                    MOJFile theFile = tempFiles.First(z => z.GetOrganizedPath().ToLower() == f.GetOrganizedPath().ToLower());

                                    DispatcherOperation op = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate
                                    {
                                        Control_DuplicateFile _ctrl_duplicate = new Control_DuplicateFile(theFile, f);
                                        WindowControl _ctrl = GlobalVars.TheHost.AddNewUserControl(_ctrl_duplicate, new WindowControlInfo(600, 450)
                                        {
                                            DefaultPosition = WindowPosition.Center,
                                            WindowTitle = MOJLocalization.Localize("Duplicate files"),
                                        });
                                        _ctrl_duplicate.OnResult += delegate
                                        {
                                            res = _ctrl_duplicate.Result;
                                            _ctrl.Close();
                                        };
                                    });
                                    while (res == -1) { }

                                    switch (res)
                                    {
                                        case 0:
                                            GlobalVars.TheHost.RemoveFileFromDataBase(f.FileID);
                                            break;

                                        case 1:
                                            for (int y = 0; y < tempFiles.Count; y++)
                                                if (tempFiles[y].FileID == theFile.FileID)
                                                {
                                                    GlobalVars.TheHost.RemoveFileFromDataBase(tempFiles[y].FileID);
                                                    tempFiles.RemoveAt(y);
                                                    break;
                                                }
                                            tempFiles.Add(f);
                                            break;

                                        case 2:
                                            for (int y = 0; y < tempFiles.Count; y++)
                                                if (tempFiles[y].FileID == theFile.FileID)
                                                {
                                                    tempFiles.RemoveAt(y);
                                                    break;
                                                }
                                            break;
                                    }
                                }
                                #endregion
                                else
                                    tempFiles.Add(f);
                            }
                    }

                    foreach (var file in tempFiles)
                        ListFiles.Add(file);
                }

                AddListBoxEntry("Checking files process completed");
                AddListBoxEntry(string.Format("{0} Files to be processed", ListFiles.Count));
                SetLoadingStatus(false);
            }
            catch (Exception ex)
            {
                GlobalVars.TheHost.ReportError(new ErrorReporter()
                {
                    ErrorCode = "asyncPreProcess",
                    ErrorMessage = "IMPOSSIBLE",
                    ErrorDetails = ex.ToString(),
                });
            }
        }
        #endregion

        private void StartProcess(object sender, RoutedEventArgs e)
        {
            _ListBox.Items.Clear();
            NoArgs th = new NoArgs(StartProcessAsync);
            SetLoadingStatus(true);
            th.BeginInvoke(null, null);
        }
        private void StartProcessAsync()
        {
            try
            {
                int count = 0;
                foreach (var v in ListFiles)
                {
                    count++;
                    string word = (_rules.KeepFileDisk || _rules.DiskID == v.DiskID) ? "Move" : "Copy";

                    AddListBoxEntry("-------------------");
                    AddListBoxEntry(string.Format("File {0}/{1}", count, ListFiles.Count));
                    AddListBoxEntry(string.Format("{0} From : {1}", word, v.FileFullPath));
                    AddListBoxEntry(string.Format("To : {1}", word, v.GetOrganizedPath()));

                    if (word == "Move")
                    {
                        string dir = IO.Path.GetDirectoryName(v.GetOrganizedPath());
                        string dirhome = IO.Path.GetDirectoryName(v.FileFullPath);

                        SetDirectoryPermissions(dir);
                        SetDirectoryPermissions(dirhome);

                        IO.File.Move(v.FileFullPath, v.GetOrganizedPath());

                        v.FilePath = v.GetOrganizedPath();
                        v.DiskID = TOOLS.GetDriveID(v.FilePath);
                        v.UpdateInfo();

                        IO.DirectoryInfo del = new IO.DirectoryInfo(dirhome);
                        if (del.EnumerateDirectories().Count() == 0 && del.EnumerateFiles().Count() == 0)
                            IO.Directory.Delete(dirhome, false);

                        AddListBoxEntry("SUCESS");
                    }
                    else
                    {
                        AddListBoxEntry("COPY PROCESS NOT IMPLEMENTED");
                    }

                    AddListBoxEntry("-------------------");
                    SetProgress(count, ListFiles.Count);
                }

                SetLoadingStatus(false);
                ListFiles.Clear();
            }
            catch (Exception ex)
            {
                GlobalVars.TheHost.ReportError(new ErrorReporter()
                {
                    ErrorCode = "Control_OrganizeMovies.StartProcessAsync",
                    ErrorMessage = "Error organizing files",
                    ErrorDetails = ex.ToString(),
                });
            }
        }
        private void SetDirectoryPermissions(string d)
        {
            IO.DirectoryInfo dir = new IO.DirectoryInfo(d);
            if (!dir.Exists)
                dir.Create();

            IdentityReference id = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
            DirectorySecurity dirSecure = dir.GetAccessControl();
            dirSecure.AddAccessRule(new FileSystemAccessRule(
                id,
                FileSystemRights.FullControl,
                InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                PropagationFlags.None,
                AccessControlType.Allow));

            dir.SetAccessControl(dirSecure);
        }

        private void StartPreview(object sender, RoutedEventArgs e)
        {
            _ListBox.Items.Clear();
            NoArgs th = new NoArgs(PreviewAsync);
            SetLoadingStatus(true);
            th.BeginInvoke(null, null);
        }
        private void PreviewAsync()
        {
            int count = 0;
            foreach (var v in ListFiles)
            {
                count++;
                string word = (_rules.KeepFileDisk || _rules.DiskID == v.DiskID) ? "Move" : "Copy";

                AddListBoxEntry("-------------------");
                AddListBoxEntry(string.Format("File {0}/{1}", count, ListFiles.Count));
                AddListBoxEntry(string.Format("{0} From : {1}", word, v.FileFullPath));
                AddListBoxEntry(string.Format("To : {1}", word, v.GetOrganizedPath()));
                AddListBoxEntry("-------------------");
            }

            SetLoadingStatus(false);
        }

        private void AddListBoxEntry(string entry)
        {
            DispatcherOperation op = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate
            {
                _ListBox.Items.Add(_ListBox.Items.Count.ToString() + "- " + entry);
                _ListBox.ScrollIntoView(_ListBox.Items[_ListBox.Items.Count - 1]);
            });
            while (op.Status == DispatcherOperationStatus.Executing) { }
        }
        private void SetProgress(int value, int max)
        {
            DispatcherOperation op = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate
            {
                _Prog_progress.Maximum = max;
                _Prog_progress.Value = value;
            });
            while (op.Status == DispatcherOperationStatus.Executing) { }
        }
        private void SetLoadingStatus(bool Value)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate
            {
                _btn_start.IsEnabled = !Value;
                _btn_preview.IsEnabled = !Value;
                _Prog_isAlive.IsIndeterminate = Value;
            });
        }
        private delegate void NoArgs();
    }
}
